﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.AccessControl;
using System.Text;
using System.Web;
using Castle.MonoRail.Framework;
using OAuth.Net.Common;
using Rodunu.Movies.Contracts;
using Rodunu.Movies.Interfaces.Activity;
using Rodunu.Movies.Interfaces.Collections;
using Rodunu.Movies.Interfaces.Movie;
using Rodunu.Movies.Interfaces.Services;
using Rodunu.Movies.Interfaces.Subscriptions;
using Rodunu.Movies.Interfaces.User;
using Rodunu.Movies.Logic.Activity;
using Rodunu.Movies.Logic.Collections;
using Rodunu.Movies.Logic.Movie;
using Rodunu.Movies.Logic.Subscriptions;
using Rodunu.Movies.Logic.User;
using Rodunu.Movies.Services.IMDB;
using Rodunu.Movies.Services.NetFlix.DataProvider.Logic;
using Rodunu.Movies.Services.NetFlix.DataProvider.NFService;
using Rodunu.Utilities.JSON;

namespace Rodunu.Movies.Web.Controllers
{
    public class ServicesController : UserBaseController
    {
        #region Private Members

        private IMovie _movieLogic;
        private IServicesMovieLink _serviceMovieLinkLogic;
        private IUser _userLogic;
        private readonly IServices _serviceLogic;
        private readonly ISubscriptions _subscriptionLogic;

        #endregion

        #region Constructor

        public ServicesController()
        {
            _userLogic = new UserLogic();
            _serviceLogic = new ServicesLogic();
            _subscriptionLogic = new SubscriptionsLogic();
        }

        #endregion

        #region IMDB

        public void SearchIMDB(string searchVariable, string linkFunction, long movieId)
        {
            SetUser();
            PropertyBag["User"] = User;
            PropertyBag["MovieId"] = movieId;
            PropertyBag["SearchVariable"] = searchVariable;
            PropertyBag["SearchVariableJS"] = searchVariable.Replace("'", "\\'");
        }

        public void ReturnResults(string searchVariable, long movieId)
        {
            SetUser();
            PropertyBag["User"] = User;
            PropertyBag["MovieId"] = movieId;

            var controller = new IMDBController();
            var search = controller.Search(searchVariable);

            foreach (var result in search.SearchResults)
            {
                switch (result.Category)
                {
                    case "Popular":
                        PropertyBag["Popular"] = result.TitleResult;
                        break;
                    case "Partial":
                        if (result.Type == "Title")
                            PropertyBag["PartialTitle"] = result.TitleResult;
                        else
                            PropertyBag["PartialName"] = result.TitleResult;
                        break;
                }
            }
        }

        public void GetIMDBInfo(string imdbId, int asJson)
        {
            SetUser();
            var controller = new IMDBController();
            try
            {
                PropertyBag["Movie"] = controller.GetMovie(imdbId);
            }
            catch (Exception ex)
            {
                RenderText("Error");
                return;
            }
            PropertyBag["ForPlacement"] = asJson;
            PropertyBag["ImdbId"] = imdbId;
        }

        public void LinkToIMDB(long movieId)
        {
            SetUser();
            _movieLogic = new MovieLogic();
            _serviceMovieLinkLogic = new ServicesMovieLinkLogic();

            Movie movie = _movieLogic.Find(movieId);
            PropertyBag["JSMovieName"] = movie.Name.Replace("'", "\\'");

            PropertyBag["Movie"] = movie;
            try
            {
                var movieLinks = _serviceMovieLinkLogic.GetServiceMoviesByMovie(movieId);
                var controller = new IMDBController();
                var imdb = new StringBuilder();
                imdb.Append("<div class='IMDBLink'>Other users have linked this movie in IMDB to:</div>");
                imdb.Append("<table class='MovieLinks'>");
                foreach (var link in movieLinks)
                {
                    LookupTitleResponse response = controller.GetMovie(link.ImdbId);
                    foreach (var data in response.TitleData)
                    {
                        imdb.Append("<tr>");
                        imdb.Append("<td class='MovieName'>");
                        imdb.Append(data.Title);
                        imdb.Append("</td>");
                        imdb.Append(@"<td class='MovieNameLink' onclick=""AddThisIMDB('");
                        imdb.Append(link.ImdbId);
                        imdb.Append("','");
                        imdb.Append(movieId.ToString());
                        imdb.Append(@"')"">");
                        imdb.Append("(ADD)");
                        imdb.Append("</td>");
                        imdb.Append("</tr>");
                    }
                }
                imdb.Append("</table>");
                PropertyBag["IMDBMovies"] = imdb.ToString();
            }
            catch (Exception ex)
            {
                
            }
        }

        public void LinkMovieToIMDB(long movieId, string imdbId, long linkId)
        {
            SetUser();
            _serviceMovieLinkLogic = new ServicesMovieLinkLogic();
            _movieLogic = new MovieLogic();
            if (linkId <= 0)
            {
                IList<ServicesMovieLink> links = _serviceMovieLinkLogic.GetServiceMoviesByUserAndMovie(
                    User.Id, movieId);
                var link = new ServicesMovieLink();
                if (links.Count > 0)
                {
                    link = links.First();
                }
                link.ImdbId = imdbId;
                link.Movie = _movieLogic.Find(movieId);
                link.UserInfo = _userLogic.Find(User.Id);

                if (link.Id > 0)
                    _serviceMovieLinkLogic.Update(link);
                else
                    _serviceMovieLinkLogic.Create(link);
            }
            //IUserActivity userActivityLogic = new UserActivityLogic();
            //userActivityLogic.Create(new UserActivity(_userLogic.Find(User.Id), "Linking Movie", DateTime.Now, (int)UserActivityTypes.LinkMovieToIMDB, movieId));

            RenderText("1:" + imdbId);
        }

        #endregion

        #region Activity

        public void SiteActivity(long id)
        {
            SetUser();
            ISiteUpdates siteUpdates = new SiteUpdatesLogic();
            PropertyBag["SiteUpdates"] = siteUpdates.Find(id);
        }

        #endregion

        public void Configure(long sid, long suid)
        {
            SetUser();
            Contracts.Services service = _serviceLogic.Find(sid);

            if (service != null)
            {
                if (service.Enabled)
                {
                    switch (service.Name.ToUpper())
                    {
                        case "IMDB":
                            break;
                        case "NETFLIX":
                            RedirectToAction("ConfNetflix");
                            break;
                        case "AMAZON":
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    RenderText("The service you requested is unavailable.");
                }
            }
            else
            {
                RenderText("The service you requested is unavailable.");
            }
        }

        #region Netflix

        public void NetflixAuthentication(string username, string password)
        {
            SetUser();
            NetflixService netflixService = new NetflixService(_userLogic.Find(User.Id));
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(netflixService.AuthorizationUri);
            string proxy = null;

            string data =
                String.Format(
                    "login={0}&password={1}&oauth_token={2}&application_name={3}&oauth_consumer_key={4}&accept_tos={5}",
                    username, password, netflixService.RequestToken.Token, netflixService.ApplicationName,
                    netflixService.ConsumerKey, "checked");
            byte[] buffer = Encoding.UTF8.GetBytes(data);

            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            req.ContentLength = buffer.Length;
            req.Proxy = new WebProxy(proxy, true); // ignore for local addresses
            req.CookieContainer = new CookieContainer(); // enable cookies

            Stream reqst = req.GetRequestStream(); // add form data to request stream
            reqst.Write(buffer, 0, buffer.Length);
            reqst.Flush();
            reqst.Close();

            try
            {
                HttpWebResponse res = (HttpWebResponse)req.GetResponse();
                string response = ServicesLogic.Parse(res);
                if (response.ToLower().Contains("successfully linked"))
                {
                    netflixService.GetAccessToken();
                    NetflixDataLogic netflixDataLogic = new NetflixDataLogic();
                    UserInfo user = _userLogic.Find(User.Id);
                    IList<NetflixTokenStore> store = netflixDataLogic.FindByBase("UserInfo", user);
                    NetflixTokenStore token = (from t in store where (TokenType)t.Type == TokenType.Access select t).SingleOrDefault();

                    if (token != null && !string.IsNullOrEmpty(user.NetflixId))
                    {
                        RenderText("Success!");
                    }
                    else
                    {
                        RenderText(response);
                    }
                }
                else
                {
                    RenderText("Fail");
                }
            }
            catch (Exception ex)
            {
                RenderText(ex.Message);
            }
            
        }

        public void ConfNetflix()
        {
            SetUser();
            SetPage(PageTypes.Profile);
            SetLayout(true);
            NetflixService netflixService = new NetflixService(_userLogic.Find(User.Id));
            netflixService.GetRequestToken();
        }

        public void LinkNetflixToMovie(string netflixId, long movieId)
        {
            SetUser();
            IMovie movieLogic = new MovieLogic();
            Movie movie = movieLogic.Find(movieId);
            movie.NetflixId = netflixId;
            movie.LastModified = DateTime.Now;
            movie.UserMovies = new List<UserMovies>();
            movieLogic.Update(movie);

            RenderText("1");
        }

        #endregion

        public void CheckIfOwnMovie(long movieId, long userMovieId)
        {
            SetUser();
            IUserMovies userMovies = new UserMoviesLogic();
            UserMovies movie = userMovies.OwnMovie(User.Id, movieId);
            if (movie != null && movie.Id > 0)
            {
                if (movie.UserCollections == null)
                    RenderText(movie.Id + ":" + movieId);
                else
                {
                    if (!String.IsNullOrEmpty(movie.Location))
                        RenderText(movie.Id + ":" + movieId + ":" + movie.UserCollections.Name + " - " + movie.Location);
                    else
                        RenderText(movie.Id + ":" + movieId + ":" + movie.UserCollections.Name);
                }
            }
            else
                RenderText("0:" + userMovieId);
        }

        public void GetAllowRequestPage(long requestId, bool allow)
        {
            SetUser();
            IFriendMovieRequest friendMovieRequestLogic = new FriendMovieRequestLogic();
            PropertyBag["MovieRequest"] = friendMovieRequestLogic.Find(requestId);
            PropertyBag["Allow"] = allow;
        }

        public void SearchForMovie(string movieName, bool doByLetter, bool forPage)
        {
            SetUser();
            if (!String.IsNullOrEmpty(movieName))
            {
                _movieLogic = new MovieLogic();

                PropertyBag["Movies"] = _movieLogic.SearchForMovies(movieName).OrderBy(o => o.Name).ToList();
            }
            else
            {
                PropertyBag["Movies"] = new List<Movie>();
            }
            PropertyBag["forPage"] = forPage;
        }

        public void SearchForUserMovie(string movieName, bool doByLetter, bool forPage)
        {
            SetUser();
            if (!String.IsNullOrEmpty(movieName))
            {
                IUserMovies _userMoviesLogic = new UserMoviesLogic();

                PropertyBag["Movies"] = _userMoviesLogic.SearchForMovies(movieName, User.Id).OrderBy(o => o.Name).ToList();
            }
            else
            {
                PropertyBag["Movies"] = new List<UserMovies>();
            }
            PropertyBag["forPage"] = forPage;
        }

        public void RemoveUserMovieFromCollection(long parentId, long userMovieId)
        {
            SetUser();
            IUserMovies userMoviesLogic = new UserMoviesLogic();
            UserMovies userMovies = userMoviesLogic.Find(userMovieId);
            if (userMovies.UserInfo.Id != User.Id) return;

            userMoviesLogic = null;
            userMovies = null;
            UserMoviesLogic userMoviesLogic2 = new UserMoviesLogic();
            UserMovies userMovies2 = userMoviesLogic2.Find(userMovieId);
            userMovies2.ParentId = null;
            userMovies2.FriendMovieRequests = new List<FriendMovieRequest>();
            userMoviesLogic2.Update(userMovies2);
            PropertyBag["MovieChildren"] = userMoviesLogic2.GetMovieChildren(parentId);
        }

        public void AddMovie()
        {
            SetUser();
            IUserCollections userCollectionsLogic = new UserCollectionsLogic();
            IMovieTypes movieTypesLogic = new MovieTypesLogic();
            ICondition userConditionLogic = new ConditionLogic();
            PropertyBag["UserCollections"] = userCollectionsLogic.GetUserCollectionsByUser(User.Id);
            PropertyBag["MovieType"] = movieTypesLogic.FindAll();
            PropertyBag["Conditions"] = userConditionLogic.FindAll();
        }

        public void GetMovieDetail(long id)
        {
            SetUser();
            _movieLogic = new MovieLogic();
            PropertyBag["Movie"] = _movieLogic.Find(id);
        }

        public void MakeMovieFavorite(long id, bool favorite)
        {
            SetUser();
            IUserMovies userMoviesLogic = new UserMoviesLogic();
            UserMovies userMovies = userMoviesLogic.Find(id);
            userMovies.IsFavorite = favorite;
            userMovies.FriendMovieRequests = new List<FriendMovieRequest>();
            userMoviesLogic.Update(userMovies);

            RenderText(id + ":" + favorite);
        }

        //private IList<Movie> GetSortedMovies(IList<Movie> movies, string movieName, bool useCount)
        //{
        //    IList<SearchResult> searchResults = new List<SearchResult>();
        //    foreach (Movie mov in movies)
        //    {
        //        searchResults.Add(new SearchResult(mov, Compute(movieName, mov.Name)));
        //    }

        //    int count = 0;
        //    IList<Movie> returnMovies = new List<Movie>();
        //    foreach (var result in searchResults.OrderBy(o => o.Rank))
        //    {
        //        if (result.Rank > 70 || (useCount && count >= 30))
        //        {
        //            return returnMovies;
        //        }
        //        returnMovies.Add(result.Movie);
        //        count++;
        //    }
        //    return returnMovies;
        //}

        //public static int Compute(string s, string t)
        //{
        //    int n = s.Length;
        //    int m = t.Length;
        //    int[,] d = new int[n + 1, m + 1];

        //    // Step 1
        //    if (n == 0)
        //    {
        //        return m;
        //    }

        //    if (m == 0)
        //    {
        //        return n;
        //    }

        //    // Step 2
        //    for (int i = 0; i <= n; d[i, 0] = i++)
        //    {
        //    }

        //    for (int j = 0; j <= m; d[0, j] = j++)
        //    {
        //    }

        //    // Step 3
        //    for (int i = 1; i <= n; i++)
        //    {
        //        //Step 4
        //        for (int j = 1; j <= m; j++)
        //        {
        //            // Step 5
        //            int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

        //            // Step 6
        //            d[i, j] = Math.Min(
        //                Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
        //                d[i - 1, j - 1] + cost);
        //        }
        //    }
        //    // Step 7
        //    return d[n, m];
        //}
        
        public void Upload(HttpPostedFile file)
        {
            SetUser();

            var directoryInfo = new DirectoryInfo(Context.Server.MapPath(@"..\Uploads") + @"\" + User.Id + @"\Avatars");
            if (!directoryInfo.Exists)
            {
                directoryInfo.Create();
            }

            string strSaveLocation = Context.Server.MapPath(@"..\Uploads") + @"\" + User.Id + @"\Avatars\" + file.FileName;
            file.SaveAs(strSaveLocation);

            IUser userLogic = new UserLogic();
            userLogic.SetAvatar(User.Id, file.FileName);

            RenderText("1:" + User.Id + @"\Avatars\" + file.FileName);
        }
    }

    public class SearchResult
    {
        public SearchResult(Movie movie, int rank)
        {
            Movie = movie;
            Rank = rank;
        }

        public Movie Movie { get; set; }
        public int Rank { get; set; }
    }
}
